#include "table.h"

void Table::table_foreignkey_join(Table& t1,string t1col, Table& t2,string t2col, Table& res) {
	int t1_fk_index = -1;
	int t2_mk_index = -1;
	for (int i = 0; i < t1.column_names.size(); i++) {
		if (t1.column_names[i] == t1col) {
			t1_fk_index = i;
		}
	}
	for (int i = 0; i < t2.column_names.size(); i++) {
		if (t2.column_names[i] == t2col) {
			t2_mk_index = i;
		}
	}
	if (t1_fk_index == -1 || t2_mk_index == -1) {
		cout << "[Error   ] fk join error no focus on col" << endl;
		exit(0);
	}

	res.table_name = "(" + t1.table_name + "_fj_" + t2.table_name + ")";
	res.dblocal = false;
	
	for (int i = 0; i < t1.column_names.size(); i++) {
		res.column_names.push_back(t1.column_names[i]);
	}
	for (int i = 0; i < t2.column_names.size(); i++) {
		res.column_names.push_back(t2.column_names[i]);
	}
	for (int i = 0; i < res.column_names.size(); i++) {
		res.values.push_back(vector<string>());
	}


	int t2_flag = 0;
	int t1_size = t1.values[0].size();
	for (int i = 0; i < t1_size; i++) {
		if (t1.values[t1_fk_index][i] == t2.values[t2_mk_index][t2_flag]) {
			int col_num = 0;
			for (int j = 0; j < t1.column_names.size(); j++) {
				res.values[j].push_back(t1.values[j][i]);
			}
			col_num = t1.column_names.size();

			for (int j = 0; j < t2.column_names.size(); j++) {
				res.values[col_num].push_back(t2.values[j][i]);
				col_num++;
			}
			t2_flag++;
			continue;
		}
		t2_flag++;
	}

}

void Table::table_print() {
	cout << "table name : " << table_name << endl;
	for (int i = 0; i < column_names.size(); i++) {
		cout << column_names[i] << "\t" ;
	}
	cout << endl;
	int t_size = values[0].size();
	for (int i = 0; i < t_size; i++) {
		for (int j = 0; j < column_names.size(); j++) {
			cout << values[j][i] << "\t";
		}
		cout << endl;
	}
}

void Table::input_data(PGconn* conn, string tablename,vector<string> colnames, string sql) {
	table_name = tablename;

	column_names = colnames;

	PGresult* res = PQexec(conn, sql.c_str());
	if (PQresultStatus(res) != PGRES_TUPLES_OK) {
		cout << "[Error   ] execute : " << sql << endl;
		PQclear(res);
		exit(0);
	}
	int res_row = PQntuples(res);
	int res_col = PQnfields(res);
	if (res_col != column_names.size()) {
		cout << "[Error] table colomn size != sql res" << endl;
		PQclear(res);
		exit(0);
	}
	for (int j = 0; j < res_col; j++) {
		values.push_back(vector<string>());
	}
	for (int i = 0; i < res_row; i++) {
		for (int j = 0; j < res_col; j++) {
			values[j].push_back(PQgetvalue(res, i, j));
		}
	}
	dblocal = true;
	cout << "[logging ] input : " << tablename << "data, rows : " << values[0].size() << endl;
}

void Table::table_normal_join(Table& t1, Table& t2, Table& res) {
	
	res.table_name = "(" + t1.table_name + "_nj_" + t2.table_name + ")";
	res.dblocal = false;

	for (int i = 0; i < t1.column_names.size(); i++) {
		res.column_names.push_back(t1.column_names[i]);
	}
	for (int i = 0; i < t2.column_names.size(); i++) {
		res.column_names.push_back(t2.column_names[i]);
	}
	for (int i = 0; i < res.column_names.size(); i++) {
		res.values.push_back(vector<string>());
	}

	int t1_row = t1.values[0].size();
	int t2_row = t2.values[0].size();
	int t1_cols = t1.column_names.size();
	int t2_cols = t2.column_names.size();

	for (int i = 0; i < t1_row; i++) {
		for (int j = 0; j < t2_row; j++) {
			for (int k = 0; k < t1_cols; k++) {
				res.values[k].push_back(t1.values[k][i]);
			}
			for (int k = 0; k < t2_cols; k++) {
				res.values[k + t1_cols].push_back(t2.values[k][j]);
			}
		}
	}

}

void Table::add_tracebit() {
	string tbit_col = table_name + "_tbit";
	column_names.push_back(tbit_col);
	values.push_back(vector<string>());
	int row = values[0].size();
	int tbit_num = values.size() - 1;
	for (int i = 0; i < row; i++) {
		values[tbit_num].push_back(to_string(i));
	}
}

void Table::execute_where(Predicate& pred){
	string left_colname = pred.left_value[0];
	int left_index = -1;
	for (int i = 0; i < column_names.size(); i++) {
		if (column_names[i] == left_colname) {
			left_index = i;
			break;
		}
	}
	if (left_index == -1) {
		cout << "[Error   ] does not exist col " << left_colname << endl;
		exit(0);
	}

	string right_value = pred.right_value[0];

	for (int i = 0; i < values[0].size(); i++) {
		if (values[left_index][i] != right_value) {
			for (int j = 0; j < column_names.size(); j++) {
				values[j][i] = values[j].back();
				values[j].pop_back();
			}
			i--;
		}
	}

}

void Table::save_todb(PGconn* conn) {
	string temp_name = table_name + "_temp";
	string del_sql = "drop table if exists " + temp_name;
	PQexec(conn, del_sql.c_str());
	string create_sql = "create table " + temp_name + "(";
	for (int i = 0; i < column_names.size(); i++) {
		if (i != column_names.size() - 1) {
			create_sql += column_names[i] + " character varying,";
		}
		else {
			create_sql += column_names[i] + " character varying)";
		}
	}
	PQexec(conn, create_sql.c_str());
	
	int total_row = values[0].size();
	int total_col = column_names.size();
	for (int i = 0; i < total_row; i++) {
		if (i % 10000 == 0) cout << i << " / " << total_row << endl;
		string insert_sql = "insert into " + temp_name + " values(";
		for (int j = 0; j < total_col; j++) {
			string value = values[j][i];
			if (j != total_col - 1) {
				insert_sql += "'" + value + "',";
			}
			else {
				insert_sql +=   value + ")";
			}
		}
		PQexec(conn, insert_sql.c_str());
	}

}